package com.example.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

import com.example.silvercare.Coalition;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.util.Log;
import app.database.friendlist.Constants;
import app.database.friendlist.FriendListDB;

public class LocationUpdateService extends Service{

	static String latitude;
	static String longitude;
	static String address;
	static String fingerprint;
	
	//simulation
	Timer timer = new Timer();
	double simulateLatitude;
	double simulateLongitude;
	double simulateFingerprintX;
	double simulateFingerprintY;
	double simulateFingerprintZ;
	
	final static double MIN_DISTANCE = 10;
	final static int MIN_TIME = 1000; //MS
	final static int MAX_TIME = 180000;//MS
	final static int SCALE = 100;
	final static int MAPSIZE = 5;
	double pre_simulateLatitude = 0;
	double pre_simulateLongitude = 0;
	double pre_simulateFingerprintX = 0;
	double pre_simulateFingerprintY = 0;
	double pre_simulateFingerprintZ = 0;
	String pre_address = "";
	double pre_time = 0;

    SharedPreferences myprefs;
    String myname;
    String myemail;
    
    FriendListDB dba;
    int TABLE = 1;
    //Map Engine
    MapEngineClient mapEngine;
    
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	public void onCreate() {
		super.onCreate();
		//Toast.makeText(this, "Service created", Toast.LENGTH_LONG).show();
 
        myprefs = PreferenceManager.getDefaultSharedPreferences(this);
        myname = myprefs.getString("namePref", null);
        myemail = myprefs.getString("emailaddressPref", null);
		
        dba = new FriendListDB(this);
		dba.open();
		
		Thread initBkgThread = new Thread(new Runnable(){
			public void run() {
		        mapEngine=new MapEngineClient();
				simulateMyCurrentLocation();
				//check for P/A notification every 1 minute
				simulateAlarm();
			}
		});
		initBkgThread.start();

	}
	
	//exceed 10m or MAX_TIME
	private boolean QueryMapEngineCondition(){
		long currentTime = System.currentTimeMillis();
		if(currentTime - pre_time > MAX_TIME || vertexDistance() > 10)
		{
			pre_time = currentTime;
			pre_simulateLatitude = simulateLatitude;
			pre_simulateLongitude = simulateLongitude;
			return true;
		}
		return false;
	}
	
	private double vertexDistance(){

		double distance = Math.sqrt((simulateLatitude - pre_simulateLatitude)*(simulateLatitude - pre_simulateLatitude) +
		(simulateLongitude - pre_simulateLongitude)*(simulateLongitude - pre_simulateLongitude));
		distance = SCALE * MAPSIZE * distance;
		return distance;
	}
	
	private void simulateMyCurrentLocation(){

		timer.scheduleAtFixedRate(new TimerTask() {

			public void run() {
				
				//0.01~1.00
				int tempLatitude = (int) (simulateLatitude*100 + 1 + 0.5);
				int tempLongitude = (int) (simulateLongitude*100 + 1 + 0.5);
            	simulateLatitude = (double)(tempLatitude % 100) / 100;
            	simulateLongitude = ((double)(tempLongitude % 100)) / 100;
            	/*
            	System.out.println("--------------------");
            	System.out.println(simulateLongitude*100);
            	System.out.println(((int)(simulateLongitude*100)));
            	System.out.println(((double)((((int)(simulateLongitude*100))+1)%100)));
            	System.out.println(((double)((((int)(simulateLongitude*100))+1)%100)) / 100);
            	System.out.println(simulateLongitude);
       			*/
            	
 				setCoordinates();
				setFingerprint();
				if(QueryMapEngineCondition())
					setAddress();	 
			}
		}, 0000, MIN_TIME);			
	}
	
	private void simulateAlarm(){
		Timer alarmTimer = new Timer();
		alarmTimer.scheduleAtFixedRate(new TimerTask() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				sendPANotification();
			}
			
		}, 0, 60000);
	}
	
	private void setCoordinates(){
    	latitude = ""+simulateLatitude*MAPSIZE;
		longitude = ""+simulateLongitude*MAPSIZE;
	}
	private void setFingerprint(){
		fingerprint = ""+simulateFingerprintX+", "+simulateFingerprintY+", "+simulateFingerprintZ;
	}
	private void setAddress(){
		pre_address = address;
		QueryMapEngine();
	}
	
	private void QueryMapEngine(){
		Thread initBkgThread = new Thread(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				//sent latitude and longitude to map engine
				
				try{
						address = mapEngine.processService(1,myname+"|"+myemail+"|"+latitude+"|"
								+longitude+"|none|none|none");
						System.out.println(myname+"|"+myemail+"|"+latitude+"|"
								+longitude+"|none|none|none");
						if(address == null)
							System.out.println("Map Engine Return Null");
						else
						{
							System.out.println("Map Engine Return "+address);
							sendELNotification();
						}
						if(mapEngine.processError == 1)
						{
							mapEngine.close();
							mapEngine = new MapEngineClient();
						}
						
				}catch(Exception e)
				{
					if(mapEngine != null && mapEngine.connection==1)
						mapEngine.close();
					mapEngine=new MapEngineClient();
					e.printStackTrace();
				}finally{

				}   
			}
			
		});
		initBkgThread.start();

	}
	
	public boolean notificationAddressStringMatch(String notification, String address)
	{
        Scanner sc=new Scanner(notification).useDelimiter("\\;");
		String s;
		while(sc.hasNext())
		{
			s = sc.next();
			if(s!=null && !s.equalsIgnoreCase(""))
			{
				if(s.equalsIgnoreCase(address))
					return true;
			}
		}
		return false;
	}
	
	//send el notification
	public class MyRunnable1 implements Runnable {
		int enteringORleaving;
		String IpAddress;
		String Port;
		String Email;
		public MyRunnable1(String e, int i) {
		       // store parameter for later user
			Email = e;
			enteringORleaving = i;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			if(getFriendConnectionInfo(Email)==0)
			{
				try{
		             Socket socket = new Socket(IpAddress,Integer.parseInt(Port));
		             //outgoing stream redirect to socket
		             message.Message msg1 = new message.Message();
		             msg1.setServiceType(4);
		             String notificationInfo;
		             if(enteringORleaving == 0)
		            	 notificationInfo = myname+" is entering "+address;
		             else 
		            	 notificationInfo = myname+" is leaving "+address;
		             msg1.setContent(myname+"|"+myemail+"|"+notificationInfo);
		             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
		             oos.writeObject(msg1);
		             
		             ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
		             message.Message msg2 = (message.Message) ois.readObject();
		             
		             //Close connection
		             socket.close();
		             
		             if(msg2.getContent()!=null)
		             {
		             	Log.d("Tcp Example", "From server: "+msg2.getContent());
		             	//if(msg2.getContent().contentEquals("OK"))
		             }
		             else
		             {
		             	Log.d("Tcp Example", "From server: "+"null");
		             }											
				}catch (UnknownHostException e) {
	             // TODO Auto-generated catch block
	             e.printStackTrace();
		        } catch (IOException e) {
	             // TODO Auto-generated catch block
	             e.printStackTrace();
		        } catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		//Request Ip address and port throught Coalition
		private int getFriendConnectionInfo(String email){
			String result = Coalition.getFriendConnectionInfo(email);
			if(result==null || !result.contains("|"))
				return -1;
			int mid = result.indexOf("|");
			String s1 = result.substring(0, mid);
			String s2 = result.substring(mid+1, result.length());
			if(s1 == null || s2 == null)
				return -1;
			IpAddress = s1;
			Port = s2;	
			return 0;
		}
	}
	
	public void sendELNotification(){
		
		Cursor c = null;
		 try {				
				c = dba.getFriends(TABLE);
				//startManagingCursor(c);
				if(c.moveToFirst()){
					do{
						String name = c.getString(c.getColumnIndex(Constants.FRIEND_NAME));
						String email = c.getString(c.getColumnIndex(Constants.EMAIL_NAME));
						String notification = c.getString(c.getColumnIndex(Constants.NOTIFICATION_NAME));
						int enteringORleaving = -1;// 0 means entering, 1 means leaving
						if(notificationAddressStringMatch(notification, address) && !pre_address.equalsIgnoreCase(address))
							enteringORleaving = 0;
						else if(notificationAddressStringMatch(notification, pre_address) && !pre_address.equalsIgnoreCase(address))
							enteringORleaving = 1;
						if(enteringORleaving != -1)
						{
							Thread initBkgThread = new Thread(new MyRunnable1(email, enteringORleaving));
							initBkgThread.start();
						}
						Log.v(name,email);
					}while(c.moveToNext());
				}
				
		 }catch(Exception e)
		 {
			 e.printStackTrace();
		 }finally{
			 if(c!=null)
			 c.close();
		 }
	}

	public boolean notificationTimeStringMatch(String notification)
	{
		
		//separate by ';'
        Scanner sc=new Scanner(notification).useDelimiter("\\;");
        while(sc.hasNext())
        {
        	String s = sc.next();
        	
        	String s1, s2;
        	int mid = s.indexOf(":");
        	s1 = s.substring(0, mid);
        	s2 = s.substring(mid+1, s.length());
        	int hour = Integer.parseInt(s1);
        	int minute = Integer.parseInt(s2);
        	Date currentdate = new Date(System.currentTimeMillis());
        	int currenthour = currentdate.getHours();
        	int currentminute   = currentdate.getMinutes();

        	if(currenthour == hour && currentminute == minute)
        		return true;		
        }
		return false;
	}
	
	//send pa notification
	public class MyRunnable2 implements Runnable {

		String IpAddress;
		String Port;
		String Email;
		
		public MyRunnable2(String e)
		{
			Email = e;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			if(getFriendConnectionInfo(Email)==0)
			{
				try{
		             Socket socket = new Socket(IpAddress,Integer.parseInt(Port));
		             //outgoing stream redirect to socket
		             message.Message msg1 = new message.Message();
		             msg1.setServiceType(5);
		             String notificationInfo = myname+" is at "+address;
		             msg1.setContent(myname+"|"+myemail+"|"+notificationInfo);
		             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
		             oos.writeObject(msg1);
		             
		             ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
		             message.Message msg2 = (message.Message) ois.readObject();
		             
		             //Close connection
		             socket.close();
		             
		             if(msg2.getContent()!=null)
		             {
		             	Log.d("Tcp Example", "From server: "+msg2.getContent());
		             	//if(msg2.getContent().contentEquals("OK"))
		             }
		             else
		             {
		             	Log.d("Tcp Example", "From server: "+"null");
		             }											
				}catch (UnknownHostException e) {
	             // TODO Auto-generated catch block
	             e.printStackTrace();
		        } catch (IOException e) {
	             // TODO Auto-generated catch block
	             e.printStackTrace();
		        } catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		//Request Ip address and port throught Coalition
		private int getFriendConnectionInfo(String email){
			String result = Coalition.getFriendConnectionInfo(email);
			if(result==null || !result.contains("|"))
				return -1;
			int mid = result.indexOf("|");
			String s1 = result.substring(0, mid);
			String s2 = result.substring(mid+1, result.length());
			if(s1 == null || s2 == null)
				return -1;
			IpAddress = s1;
			Port = s2;	
			return 0;
		}
	}
	
	public void sendPANotification(){
		Cursor c = null;
		 try {
				
				c = dba.getFriends(TABLE);
				//startManagingCursor(c);
				if(c.moveToFirst()){
					do{
						String name = c.getString(c.getColumnIndex(Constants.FRIEND_NAME));
						String email = c.getString(c.getColumnIndex(Constants.EMAIL_NAME));
						String time = c.getString(c.getColumnIndex(Constants.DATE_NAME));
						
						if(notificationTimeStringMatch(time))
				        {
				        	Thread initBkgThread = new Thread(new MyRunnable2(email));
							initBkgThread.start();
				        }
					}while(c.moveToNext());
				}
				
		 }catch(Exception e)
		 {
			 e.printStackTrace();
		 }finally{
			 if(c!=null)
			 c.close();
		 }		
	}
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		if(mapEngine != null && mapEngine.connection==1)
			mapEngine.close();
		timer.cancel();
		dba.close();
		super.onDestroy();
	}
}
